package cn.broadmax.boot.util;

import cn.broadmax.boot.base.model.LoginUser;
import cn.broadmax.boot.exception.TokenExpireException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import jexx.time.DateUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * jwt工具类
 * @author jeff
 * @date 2020/6/14
 */
@Slf4j
public class JwtUtils {

    public static final String secret = "jexx";
    /** 令牌过期时间 */
    public static final int EXPIRATION = 1000*60*60*24;

    public static String generateToken(LoginUser user) {
        return generateToken(user, new Date());
    }

    public static String generateToken(LoginUser user, Date startTime) {
        return generateToken(user, startTime, EXPIRATION);
    }

    public static String generateToken(LoginUser user, Date startTime, int timeout) {
        Date endTime = DateUtil.offsetMillisecond(startTime, timeout);
        return generateToken(user, startTime, endTime);
    }

    public static String generateToken(LoginUser user, Date startTime, Date endTime) {
        if (startTime == null || endTime == null || startTime.after(endTime)) {
            throw new IllegalArgumentException("参数异常");
        }
        Map<String, Object> claims = new HashMap<>(3);
        claims.put("userId",user.getUserId());
        return generateToken(claims, startTime, endTime);
    }

    private static String generateToken(Map<String, Object> claims) {
        Date startTime = new Date();
        Date endTime = DateUtil.offsetMillisecond(startTime, EXPIRATION);
        return generateToken(claims, startTime, endTime);
    }

    private static String generateToken(Map<String, Object> claims, Date startTime, Date endTime) {
        if (startTime == null || endTime == null || startTime.after(endTime)) {
            throw new IllegalArgumentException("参数异常");
        }
        return Jwts.builder().setClaims(claims)
                .setNotBefore(startTime)
                .setExpiration(endTime)
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 刷新令牌
     *
     * @param token 原令牌
     * @return 新令牌
     */
    public static String refreshToken(String token) {
        Claims claims = getClaimsFromToken(token);
        if(claims == null){
            throw new TokenExpireException();
        }
        return generateToken(claims);
    }

    /**
     * 验证令牌
     * @param token  令牌
     * @return 是否有效
     */
    public static boolean validateToken(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            return claims != null;
        }
        catch (ExpiredJwtException e){
            //skip
        }
        return false;
    }

    public static LoginUser parseToken(String token) throws TokenExpireException {
        Claims claims = getClaimsFromToken(token);
        if(claims == null){
            return null;
        }
        String userId = claims.get("userId", String.class);

        LoginUser user = new LoginUser();
        user.setUserId(userId);
        return user;
    }

    /**
     * 从令牌中获取数据声明, 过去返回空
     * @param token 令牌
     * @return 数据声明
     */
    private static Claims getClaimsFromToken(String token) throws TokenExpireException {
        try {
            return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        }
        catch (ExpiredJwtException e){
            throw new TokenExpireException();
        }
        catch (Exception e){
            log.error("", e);
        }
        return null;
    }

}
